package com.xlabs.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Widget;

import java.util.HashMap;
import java.util.Map;

/**
 * Chromeless Player API
 *
 * @author Uwe Maurer
 */
public class ChromelessPlayer extends Widget {

    /**
     * Player state.
     */
    public enum PlayerState {
        STOPPED,
        PLAYING,
        PAUSED,
        LOADING,
        CUED,
    }

    /**
     * Listener interface for youtube player.
     */
    public interface PlayerListener {
        /**
         * Called on video ready.
         */
        public void onReady();

        /**
         * Called on player's state change.
         *
         * @param state the new state.
         */
        public void onStateChange(PlayerState state);
    }

    /**
     * The java script object of the player.
     */
    public static class YTPlayer extends JavaScriptObject {
        /**
         * Initializes an instance of YTPlayer .
         */
        protected YTPlayer() {
        }

        /**
         * loads a video by id.
         *
         * @param videoId videoId.
         * @param startSeconds second to start from.
         */
        public native final void loadVideoById(String videoId, int startSeconds) /*-{
                            this.loadVideoById(videoId, startSeconds);
            }-*/;

        /**
         * Sets the size of the player.
         *
         * @param width  Width in pixels.
         * @param height Height in pixels.
         */
        public native final void setSize(int width, int height) /*-{
                    this.setSize(width, height);
            }-*/;

        /**
         * Sets the volume of the player.
         *
         * @param volume The volume of the player.
         */
        public native final void setVolume(int volume) /*-{
                    this.setVolume(volume);
            }-*/;

        /**
         * Pauses the video.
         */
        public native final void pauseVideo() /*-{
            this.pauseVideo();
        }-*/;

        /**
         * Pauses the video.
         */
        public native final void playVideo() /*-{
            this.playVideo();
        }-*/;

        /**
         * Returns the current time of the video.
         * @return time of the video in seconds.
         */
        public native final double getTime() /*-{
            return this.getCurrentTime();
        }-*/;

        public native final void seekTime(int seconds) /*-{
            this.seekTo(seconds, false);            
        }-*/;
    }

    /**
     * Holds a mapping from player names to actual player objects.
     */
    private static final Map<String, ChromelessPlayer> map = new HashMap<String, ChromelessPlayer>();

    static {
        register();
    }

    private static native void register() /*-{
      $wnd.onYouTubePlayerReady = function(playerId) {
            var ytplayer = $wnd.document.getElementById(playerId + "api");
            @com.xlabs.client.ChromelessPlayer::onReady(Ljava/lang/String;Lcom/xlabs/client/ChromelessPlayer$YTPlayer;)(playerId, ytplayer);
            var name = 'onPlayerStateChange' +playerId;
            $wnd[name]  = function(state) {
                    @com.xlabs.client.ChromelessPlayer::onStateChange(Ljava/lang/String;I)(playerId, state);
            }
            ytplayer.addEventListener("onStateChange", name);
        }
    }-*/;

    @SuppressWarnings("unused")
    private static void onReady(String playerId, YTPlayer playerElement) {
        ChromelessPlayer player = map.get(playerId);
        if (player != null) {
            player.player = playerElement;
            if (player.listener != null) {
                player.listener.onReady();
            }
        }
    }

    @SuppressWarnings("unused")
    private static void onStateChange(String playerId, int state) {
        ChromelessPlayer player = map.get(playerId);
        if (player != null && player.listener != null && state >= 0 && state < PlayerState.values().length) {
            player.listener.onStateChange(PlayerState.values()[state]);
        }
    }

    /**
     * Name of this player.
     */
    private final String name;

    /**
     * The player element.
     */
    private YTPlayer player;

    /**
     * Listener for player's state changes.
     */
    private PlayerListener listener;

    /**
     * Initializes an instance of ChromelessPlayer.
     *
     * @param name
     */
    public ChromelessPlayer(String name) {
        Element elem = DOM.createDiv();
        elem.setId(name);
        setElement(elem);
        this.name = name;
        map.put(name, this);
    }

    /**
     * Registers the listender and creates the swf object that plays the video.
     *
     * @param width    Width of the video object.
     * @param height   Height of the vidoe object.
     * @param listener Listener to be told about swf object state changes.
     */
    public void createSwf(int width, int height, PlayerListener listener) {
        this.listener = listener;
        createSwf(name, width, height);
    }

    /**
     * Creates the actual swf object.
     *
     * @param width    Width of the video object.
     * @param height   Height of the vidoe object.
     */
    private native void createSwf(String name, int width, int height) /*-{
         var params = { allowScriptAccess: "always", bgcolor: "#000000" };
         var atts = { id: name + "api" };
         $wnd.swfobject.embedSWF("http://www.youtube.com/apiplayer?enablejsapi=1&playerapiid=" + name,
            name, ""+width, ""+height, "8", null, null, params, atts);

    }-*/;

    /**
     * Loads a video by id.
     *
     * @param videoId      The id of the video.
     * @param startSeconds Second to start from.
     */
    public void loadVideoById(String videoId, int startSeconds) {
        if (player != null) {
            player.loadVideoById(videoId, startSeconds);
        }
    }

    /**
     * Pauses the video.
     */
    public void pauseVideo() {
        if (player != null) {
            player.pauseVideo();
        }
    }

    /**
     * Plays the loaded video.
     */
    public void playVideo() {
        if (player != null) {
            player.playVideo();
        }
    }

    /**
     * Seeks the video to the given time.
     * @param time time to play.
     */
    public void seekTime(double time)
    {
        if (player != null)
        {
            player.seekTime((int) time);
        }

    }

    /**
     * returns the current time of the video.
     * @return time of the video.
     */
    public double getTime() {
        if (player != null) {
            return player.getTime();
        }

        return -1;
    }


    /**
     * Sets the size of the player object.
     *
     * @param width  width in pixel.
     * @param height height in pixel.
     */
    public void setSize(int width, int height) {
        if (player != null) {
            player.setSize(width, height);
        }
    }

    /**
     * Sets the volume of the player.
     *
     * @param volume target volume.
     */
    public void setVolume(int volume) {
        if (player != null) {
            player.setVolume(volume);
        }
    }

    /**
     * Gets the element object of the player.
     *
     * @return player's element.
     */
    public Element getPlayer() {
        return player.cast();
    }

}
